/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "TextureReflection.h"
#include <lib3d/hard/Hardware.h>
#include <xml/Stream.h>
#include <Color.h>
#include <lib3d/hard/Texture.h>
#include <safe_new.h>

namespace liba
{
namespace lib3d
{
namespace material
{

void TextureReflectionRep::load(const TextureSimpleName & name)
{
	if( !pl )
		pl.reset(new pictureformat::Loader(name.image));
	if( !pl->is_ready() )
		return;
	if( !pl->is_valid() )
		THROW(GluckBadResource( __FUNCTION__, "pl is not valid", name.image ));
	if( pl->get_height() % 6 != 0 )
		THROW(GluckBadResource( __FUNCTION__, "pl->get_height() is not multiply of 6", name.image ));
	HardVector::iterator it = hard_vector.begin();
	for( ;it != hard_vector.end(); ++it )
	{
		if(!it->first->is_operational())
			continue;

		int mipmap_levels = material::Texture::get_mipmap_levels( pl.get() );
		if( !it->second )
			it->second = it->first->create_texture_cubic( mipmap_levels, pl->get_best_format(), pl->get_width(), pl->get_height()/6 );
		if( !it->second->is_valid() )
		{
			// can be created less mipmaps, then requested
			for( int m = 0; m != it->second->get_mipmap_levels(); ++m )
			{
				pl->reset( it->second->get_hardware_format(), m );
				for( int plane = 0; plane !=6; ++plane )
				{
					int stride = 0;
					void * dst = it->second->lock(m, plane, &stride);
					if( !dst )
					{
						plane = 6;
						continue;
					}
					// Load data from pl
					for( int i = 0; i != pl->get_height(m)/6; ++i )
					{
						pl->unpack_scanline(dst);
						dst = reinterpret_cast<char *>(dst) + stride;
					}
					it->second->unlock(m, plane);
				}
			}
		}
	}
	pl.reset();
	stop_loading();
}

void TextureReflectionRep::render_to_list( hard::Hardware * hardware, hard::RenderTexture * render_texture )
{
	hard::TextureCubic * tex = find_data( hardware );
	if( !tex || !tex->is_valid() )
	{
		start_loading();
		return;
	}
	render_texture->texture = tex;
}

void TextureReflectionRep::on_add_hardware(hard::Manager::hardware_type * ha)
{
	hard_vector.push_back( SweetPair(ha, (liba::lib3d::hard::TextureCubic*)0) );
	start_loading();
}

TextureReflection * TextureReflection::clone()const
{
	return new TextureReflection(*this);
}

} // namespace material
} // namespace lib3d
} // namespace liba

